package org.csu.mall.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.api.R;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.csu.mall.common.CONSTANT;
import org.csu.mall.common.ResponseCode;
import org.csu.mall.common.UniformResponse;
import org.csu.mall.entity.Account;
import org.csu.mall.entity.OnlineUser;
import org.csu.mall.persistence.AccountMapper;
import org.csu.mall.persistence.OnlineUserMapper;
import org.csu.mall.service.IAccountService;
import org.csu.mall.util.*;
import org.csu.mall.vo.AccountListVO;
import org.csu.mall.vo.AccountVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;

@Service("accountService")
public class IAccountServiceImpl implements IAccountService {

    @Autowired
    private AccountMapper accountMapper;

    @Autowired
    private OnlineUserMapper onlineUserMapper;

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public UniformResponse<Account> login(String username, String password) {
        int row = accountMapper.selectCount(Wrappers.<Account>query().eq("username", username));
        if(row == 0){
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.USERNAME_NOT_EXIST.getCode(), ResponseCode.USERNAME_NOT_EXIST.getDescription());
        }
        String md5Password = MD5Util.md5Encrypt32Upper(password);
        Account account = accountMapper.selectOne(
                Wrappers.<Account>query().eq("username", username).eq("password", md5Password));
        if(account == null){
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.USERNAME_PASSWORD_ERROR.getCode(), ResponseCode.USERNAME_PASSWORD_ERROR.getDescription());
        }

        //插入在线用户
        OnlineUser onlineUser = new OnlineUser();
        onlineUser.setUserId(account.getUserId());
        onlineUser.setPassword(md5Password);
        onlineUser.setUsername(username);
        onlineUser.setCreateTime(LocalDateTime.now());
        onlineUserMapper.insert(onlineUser);

//        account.setPassword(StringUtils.EMPTY);
//        AccountVO accountVO = this.entityToVO(account);
        return UniformResponse.createForSuccess(ResponseCode.SUCCESS.getDescription(), account);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public UniformResponse<String> register(Account account) {
        int row = accountMapper.selectCount(
                Wrappers.<Account>query().eq("username", account.getUsername()));
        if(row > 0){
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.USERNAME_EXIST.getCode(), ResponseCode.USERNAME_EXIST.getDescription());
        }
        row = accountMapper.selectCount(
                Wrappers.<Account>query().eq("email", account.getUsername()));
        if(row > 0){
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.EMAIL_EXIST.getCode(), ResponseCode.EMAIL_EXIST.getDescription());
        }
        row = accountMapper.selectCount(Wrappers.<Account>query().eq("phone_number", account.getPhoneNumber()));
        if(row > 0){
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.PHONE_NUMBER_EXIST.getCode(), ResponseCode.PHONE_NUMBER_EXIST.getDescription());
        }
        account.setUserId(0);
        account.setRole(CONSTANT.Role.CUSTOMER);
        //MD5密码加密
        account.setPassword(MD5Util.md5Encrypt32Upper(account.getPassword()));
        account.setCreateTime(LocalDateTime.now());
        account.setUpdateTime(LocalDateTime.now());

        row = accountMapper.insert(account);
        if(row == 0){
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.ERROR.getCode(), ResponseCode.ERROR.getDescription());
        }
        return UniformResponse.createForSuccessMessage(ResponseCode.SUCCESS.getDescription());
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public UniformResponse<String> checkField(String type, String value) {
        if(StringUtils.isNoneBlank(type, value)){
            if(CONSTANT.USERNAME.equals(type)){
                int row = accountMapper.selectCount(Wrappers.<Account>query().eq("username", value));
                if(row > 0){
                    return UniformResponse.createForErrorCodeMessage(
                            ResponseCode.USERNAME_EXIST.getCode(), ResponseCode.USERNAME_EXIST.getDescription());
                }
            } else if(CONSTANT.EMAIL.equals(type)){
                int row = accountMapper.selectCount((Wrappers.<Account>query().eq("email", value)));
                if(row > 0){
                    return UniformResponse.createForErrorCodeMessage(
                            ResponseCode.EMAIL_EXIST.getCode(), ResponseCode.EMAIL_EXIST.getDescription());
                }
            } else if(CONSTANT.PHONE_NUMBER.equals(type)){
                int row = accountMapper.selectCount(Wrappers.<Account>query().eq("phone_number", value));
                if(row > 0){
                    return UniformResponse.createForErrorCodeMessage(
                            ResponseCode.PHONE_NUMBER_EXIST.getCode(), ResponseCode.PHONE_NUMBER_EXIST.getDescription());
                }
            }else{
                return UniformResponse.createForErrorCodeMessage(
                        ResponseCode.ILLEGAL_ARGUMENT.getCode(), ResponseCode.ILLEGAL_ARGUMENT.getDescription());
            }
        }else {
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.ILLEGAL_ARGUMENT.getCode(), ResponseCode.ILLEGAL_ARGUMENT.getDescription());
        }
        return UniformResponse.createForSuccessMessage(ResponseCode.SUCCESS.getDescription());
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public UniformResponse<String> forgetPassword(String type, String value) {
        UniformResponse response = this.checkField(type, value);
        if(response.isSuccess()){
            return response;
        }
        QueryWrapper<Account> queryWrapper = new QueryWrapper<>();
        if(CONSTANT.USERNAME.equals(type)){
            queryWrapper.select("username","question").eq("username", value);

        }else if(CONSTANT.EMAIL.equals(type)){
            queryWrapper.select("username","question").eq("email", value);
        }else{
            queryWrapper.select("username","question").eq("phone_number", value);
        }
        String question = accountMapper.selectOne(queryWrapper).getQuestion();
        if(StringUtils.isNotBlank(question)){
            return UniformResponse.createForSuccess(ResponseCode.SUCCESS.getDescription(), question);
        }
        return UniformResponse.createForErrorCodeMessage(
                ResponseCode.QUESTION_NOT_EXIST.getCode(), ResponseCode.QUESTION_NOT_EXIST.getDescription());
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public UniformResponse<String> checkAnswer(String username, String question, String answer) {
        int row = accountMapper.selectCount(
                Wrappers.<Account>query().eq("username", username).eq("question", question)
        .eq("answer", answer));
        if(row > 0){
            String forgetToken = UUID.randomUUID().toString();
            TokenCacheUtil.setToken(username, forgetToken);
            return UniformResponse.createForSuccess(ResponseCode.SUCCESS.getDescription(), forgetToken);
        }
        return UniformResponse.createForErrorCodeMessage(
                ResponseCode.ANSWER_ERROR.getCode(), ResponseCode.ANSWER_ERROR.getDescription());
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public UniformResponse<String> forgetReset(String username, String forgetToken, String newPassword) {
        UniformResponse response = this.checkField("username", username);
        if(response.isSuccess()){
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.USERNAME_NOT_EXIST.getCode(), ResponseCode.USERNAME_NOT_EXIST.getDescription());
        }
        if(!TokenCacheUtil.getToken(username).equals(forgetToken)){
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.TOKEN_ERROR_TIMEOUT.getCode(), ResponseCode.TOKEN_ERROR_TIMEOUT.getDescription());
        }
        Account account = new Account();
        account.setPassword(MD5Util.md5Encrypt32Upper(newPassword));
        account.setUpdateTime(LocalDateTime.now());
        int row = accountMapper.update(account, Wrappers.<Account>query().eq("username", username));
        if(row > 0){
            return UniformResponse.createForSuccessMessage(ResponseCode.SUCCESS.getDescription());
        }
        return UniformResponse.createForErrorCodeMessage(
                ResponseCode.ERROR.getCode(), ResponseCode.ERROR.getDescription());
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public UniformResponse<String> resetPassword(Account account, String oldPassword, String newPassword, String answer) {
        if(account == null){
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.USER_NOT_LOGIN.getCode(), ResponseCode.USER_NOT_LOGIN.getDescription());
        }
        String username = account.getUsername();
        String question = account.getQuestion();
        UniformResponse response = this.checkAnswer(username, question, answer);
        if(!response.isSuccess()){
            return response;
        }
        String password = accountMapper.selectOne(
                Wrappers.<Account>query().select("password").eq("username", username)).getPassword();
        if(MD5Util.md5Encrypt32Upper(oldPassword).equals(password)){
            String md5Password = MD5Util.md5Encrypt32Upper(newPassword);
            Account upAccount = new Account();
            upAccount.setPassword(md5Password);
            upAccount.setUpdateTime(LocalDateTime.now());
            int row = accountMapper.update(upAccount, Wrappers.<Account>query().eq("username", username));
            if(row > 0){
                return UniformResponse.createForSuccessMessage(ResponseCode.SUCCESS.getDescription());
            }
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.ERROR.getCode(), ResponseCode.ERROR.getDescription());
        }
        return UniformResponse.createForErrorCodeMessage(
                ResponseCode.USERNAME_PASSWORD_ERROR.getCode(), ResponseCode.USERNAME_PASSWORD_ERROR.getDescription());
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public UniformResponse<Account> modifyAccountInfo(Account account, Account oldAccount) {
        if(oldAccount == null){
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.USER_NOT_LOGIN.getCode(), ResponseCode.USER_NOT_LOGIN.getDescription());
        }
        if(MD5Util.md5Encrypt32Upper(account.getPassword()).equals(oldAccount.getPassword())){
            oldAccount.setUsername(account.getUsername());
            oldAccount.setPhoneNumber(account.getPhoneNumber());
            oldAccount.setEmail(account.getEmail());
            oldAccount.setQuestion(account.getQuestion());
            oldAccount.setAnswer(account.getAnswer());
            int row = accountMapper.update(oldAccount, Wrappers.<Account>query().eq("user_id", oldAccount.getUserId()));
            if(row > 0){
                return UniformResponse.createForSuccess(ResponseCode.SUCCESS.getDescription(), oldAccount);
            }
        }
        return UniformResponse.createForErrorCodeMessage(
                ResponseCode.USERNAME_PASSWORD_ERROR.getCode(), ResponseCode.USERNAME_PASSWORD_ERROR.getDescription());
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public UniformResponse<AccountVO> getAccount(Account account) {
        if(account == null){
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.USER_NOT_LOGIN.getCode(), ResponseCode.USER_NOT_LOGIN.getDescription());
        }
        String username = account.getUsername();
        Account upAccount = accountMapper.selectOne(Wrappers.<Account>query().eq("username", username));
        if(upAccount == null){
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.USERNAME_NOT_EXIST.getCode(), ResponseCode.USERNAME_NOT_EXIST.getDescription());
        }
        AccountVO accountVO = entityToVO(upAccount);
        return UniformResponse.createForSuccess(ResponseCode.SUCCESS.getDescription(), accountVO);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public UniformResponse<String> authentication(Account account, String realName, Long idCard, String answer) {
        if(account == null){
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.USER_NOT_LOGIN.getCode(), ResponseCode.USER_NOT_LOGIN.getDescription());
        }
        String username = account.getUsername();
        String question = account.getQuestion();
        //检查问题答案
        UniformResponse response = this.checkAnswer(username, question, answer);
        if(!response.isSuccess()){
            return response;
        }
        //检查idcard是否已认证
        int row = accountMapper.selectCount(Wrappers.<Account>query().eq("id_card", idCard));
        if(row > 0){
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.ID_CARD_REGISTER.getCode(), ResponseCode.ID_CARD_REGISTER.getDescription());
        }
        Account upAccount = new Account();
        upAccount.setRole(CONSTANT.Role.AUTHENTICATION);
        upAccount.setRealName(realName);
        upAccount.setIdCard(idCard);
        upAccount.setUpdateTime(LocalDateTime.now());

        row = accountMapper.update(upAccount, Wrappers.<Account>query().eq("username", username));
        if(row > 0){
            return UniformResponse.createForSuccessMessage(ResponseCode.SUCCESS.getDescription());
        }
        return UniformResponse.createForErrorCodeMessage(
                ResponseCode.ERROR.getCode(), ResponseCode.ERROR.getDescription());
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public UniformResponse<Account> rechargeAccount(Account account, Double balance) {
        if(account == null){
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.USER_NOT_LOGIN.getCode(), ResponseCode.USER_NOT_LOGIN.getDescription());
        }
        account.setBalance(account.getBalance()+ balance);
        int row = accountMapper.updateById(account);
        if(row == 0){
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.ERROR.getCode(), ResponseCode.ERROR.getDescription());
        }
        return UniformResponse.createForSuccess(ResponseCode.SUCCESS.getDescription(), account);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public UniformResponse<Account> addAddress(Account account, String address) {
        if(account == null){
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.USER_NOT_LOGIN.getCode(), ResponseCode.USER_NOT_LOGIN.getDescription());
        }

        if(StringUtils.isNotBlank(account.getAddress())){
            address = new StringBuilder().append(account.getAddress()).append(";").append(address).toString();
        }
        account.setAddress(address);
        int row = accountMapper.updateById(account);
        if(row == 0){
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.ERROR.getCode(), ResponseCode.ERROR.getDescription());
        }
        return UniformResponse.createForSuccess(ResponseCode.SUCCESS.getDescription(), account);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public UniformResponse<String> logout(Account account) {
        if(account == null){
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.USER_NOT_LOGIN.getCode(), ResponseCode.USER_NOT_LOGIN.getDescription());
        }
        int row = onlineUserMapper.deleteById(account.getUserId());
        if(row == 0){
            return UniformResponse.createForErrorCodeMessage(ResponseCode.ERROR.getCode(), ResponseCode.ERROR.getDescription());
        }
        return UniformResponse.createForSuccessMessage(ResponseCode.SUCCESS.getDescription());
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public UniformResponse<AccountListVO> getAccountList(Integer role, String username, int pageSize, int pageNum) {
        Page<Account> result = new Page<>();
        result.setCurrent(pageNum);
        result.setSize(pageSize);

        QueryWrapper<Account> queryWrapper = new QueryWrapper();
        List<Integer> idList = Lists.newArrayList();
        //查询在线用户
        if(role == CONSTANT.Role.ONLINE_ADMIN){
            List<OnlineUser> onlineUserList = onlineUserMapper.selectList(null);
            for(OnlineUser onlineUser: onlineUserList){
                idList.add(onlineUser.getUserId());
            }
            queryWrapper.in("user_id", idList);
        }
        //增加用户角色查询
        if(role < CONSTANT.Role.ONLINE_ADMIN){
            queryWrapper.eq("role", role);
        }
        //指定用户名查询
        if(StringUtils.isNotBlank(username)){
            queryWrapper.eq("username", username);
        }
        result = accountMapper.selectPage(result, queryWrapper);
        if(result == null){
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.ERROR.getCode(), ResponseCode.ERROR.getDescription());
        }
        AccountListVO accountListVO = this.pageToVO(result);
        return UniformResponse.createForSuccess(ResponseCode.SUCCESS.getDescription(), accountListVO);
    }


    @Override
    public UniformResponse<Account> updateAccountImage(String imgAddress, Account account) {
        if(account == null){
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.USER_NOT_LOGIN.getCode(), ResponseCode.USER_NOT_LOGIN.getDescription());
        }
        if(StringUtils.isBlank(imgAddress)){
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.ILLEGAL_ARGUMENT.getCode(), ResponseCode.ILLEGAL_ARGUMENT.getDescription());
        }
        String[] str = imgAddress.split("\\\\");
        String img = new StringBuilder().append(account.getUserId()).append(str[str.length - 1]).toString();
        account.setImage(img);
        QiniuUtil.upload(imgAddress, img);
        int row = accountMapper.updateById(account);
        if(row == 0){
            return UniformResponse.createForErrorCodeMessage(
                    ResponseCode.ERROR.getCode(), ResponseCode.ERROR.getDescription());
        }
        return UniformResponse.createForSuccess(ResponseCode.SUCCESS.getDescription(), account);
    }

    private AccountVO entityToVO(Account account){
        AccountVO accountVO = new AccountVO();
        accountVO.setUserId(account.getUserId());
        accountVO.setUsername(account.getUsername());
        accountVO.setPhoneNumber(account.getPhoneNumber());
        accountVO.setEmail(account.getEmail());
        accountVO.setRole(account.getRole());
        accountVO.setAddress(account.getAddress());
        accountVO.setImage(account.getImage());
        accountVO.setBalance(account.getBalance());
        accountVO.setQuestion(account.getQuestion());


        //新增或修改属性
        accountVO.setCreateTime(DateUtil.localDateTimeToString(account.getCreateTime()));
        accountVO.setUpdateTime(DateUtil.localDateTimeToString(account.getUpdateTime()));
        accountVO.setImageHost(PropertiesUtil.getProperty("image.server.url"));
        if(StringUtils.isNotBlank(account.getAddress())){
            String[] addresses = account.getAddress().split(";");
            for(String item: addresses){
                accountVO.getAddressList().add(item);
            }
        }
        return accountVO;
    }

    private AccountListVO pageToVO(Page<Account> result){
        AccountListVO accountListVO = new AccountListVO();
        accountListVO.setPageNum(result.getCurrent());
        accountListVO.setPageSize(result.getSize());
        accountListVO.setStartRow(1);
        accountListVO.setEndRow(result.getPages());
        accountListVO.setTotal(result.getTotal());
        accountListVO.setPages(result.getPages());
        List<Account> accountList = result.getRecords();
        List<AccountVO> accountVOList = Lists.newArrayList();
        for(Account account: accountList){
            accountVOList.add(this.entityToVO(account));
        }
        accountListVO.setAccountVOList(accountVOList);
        accountListVO.setFirstPage(1l);
        accountListVO.setPrePage(result.getCurrent() - 1);
        accountListVO.setNextPage(result.getCurrent() + 1);
        accountListVO.setIsFirstPage(result.getCurrent() == 1);
        accountListVO.setIsLastPage(result.getCurrent() == result.getPages());
        accountListVO.setHasPreviousPage(result.getCurrent() > 1);
        accountListVO.setHasNextPage(result.getCurrent() < result.getPages());
        accountListVO.setImageHost(PropertiesUtil.getProperty("image.server.url"));
        return accountListVO;
    }
}
